
--------------------------------------------------
--- Copyright：  迷你玩-海马
--- Description：从管理中心服务器同步lua配置文件
--- 功能: 向center查询指定名字的配置文件是否有更新
--------------------------------------------------

local require  = require;
local ngx      = ngx;
local debug    = debug;
local string   = string;
local tonumber = tonumber;
local setmetatable = setmetatable;
local pairs = pairs
local type  = type

local cjson	= require('cjson.safe')

local ngx_re_match = ngx.re.match

----数据变量----
local uu         = require("modules.commhm.utils");
local log        = require("modules.commhm.log");
local ns_time    = require("modules.commhm.time");

local CLuaConfig = require("modules.center_server.CLuaConfig");
local ns_network = require("modules.commhm.network");

local ns_auth_comm_checker = require("modules.commhm.auth_comm_checker")
local CNgxTimerWrap        = require("modules.commhm.ngxTimerWrap" )

local ns_const_server_config = require("modules.commhm.const_server_config");
local ns_config              = require("modules.center_server.center_config")

local gg                     = require("modules.center_server.center_gg")
local ns_configMgr           = require("modules.center_server.configMgr")


local table = table
local table_concat =table.concat

local FOO = {
    _VERSION = '0.12.1',
    server_route_config = CLuaConfig:new( ns_config.center_lua_config_dir_root,
            "registerMaGateRoute", ns_config.debug )
};



local __route_servers_cache_key__ = 'register_route_server'


-- 两个配置的ip和port是否完全一致
function FOO.is_same_ip_port( a, b )
    return (a.ip == b.ip and a.port == b.port)
end


-- 注册一个url路由
function FOO.register_route()

    -- /data/centerConfigServer/ma/registerMaGateRoute.lua
    local config_file_path_ = FOO.server_route_config:getFullPath()
    log.debug( 'config_file_path=' .. config_file_path_ )

    local info_ = uu.read_table_file( config_file_path_ ) or { servers={} }

    local url_, functionName_
    if  not ngx.ctx.m_params.url then
        -- read from post
        ngx.req.read_body();
        local t = cjson.decode( ngx.req.get_body_data() )
        if  type(t) == 'table' then
            if  t.url then
                --{["url"]="http://10.80.240.84:1288/gm/merge/",["__cluster__"]="qqy",["path"]="gm.merge"}
                log.day_list( 'center_server', 'register_route', "read_body", uu.to_str(t) )
                url_ = t.url
            end
            if  t.functionName and #t.functionName > 0 then
                functionName_ = t.functionName
                log.debug( 'functionName=' .. uu.to_str(functionName_) )
            end
        end
    else
        url_          = ngx.ctx.m_params.url
        functionName_ = ngx.ctx.m_params.functionName
        log.debug( 'functionName=' .. uu.to_str(functionName_) )
    end

    if  not url_ then
        gg.return_table( { ret=99, msg='error_no_url' } )
        return
    end

    local m_, err = ngx_re_match(url_, [[^(?:(http[s]?):)?//([^:/\?]+)(?::(\d+))?([^\?]*)\??(.*)]], "jo")
    if  err then
        log.error( 'error_url=' .. url_ )
        gg.return_table( { ret=99, msg='error_url' } )
        return
    end

    if  type(m_) == 'table' and m_[2] and m_[3] and m_[4] then
        uu.var_dump( m_ )
        --http://120.24.64.132:8087/miniw/php_cmd?aa=bbb&cc=dd
        --[0]=http://120.24.64.132:8087/miniw/php_cmd?aa=bbb,
        --[1]=http,
        --[2]=120.24.64.132,
        --[3]=8087,
        --[4]=/miniw/php_cmd,     --/a/b
        --[5]=aa=bbb, (如果是get请求，不转码参数会不全)
    else
        --格式出错
        gg.return_table( { ret=99, msg='error_url_format' } )
        return
    end


    local tmp_      = { ip=m_[2], port=tonumber(m_[3]), t=uu.now() }
    local uri_path_ = m_[4]
    if  not (tmp_.ip and tmp_.port and #uri_path_>2 ) then
        gg.return_table( { ret=99, msg='error_url_parse' } )
        return
    end


    if  ngx.ctx.m_params.del == '1' then
        -- 从config中删除
        if  info_.servers[uri_path_] then
            -- 1 删除__LOOP__ 中的元素
            local del_loop_info_
            if  functionName_ then
                if  info_.servers[uri_path_].act_cmds and
                        info_.servers[uri_path_].act_cmds[ functionName_ ]
                then
                    del_loop_info_ = info_.servers[uri_path_].act_cmds[ functionName_ ].__LOOP__
                end
            else
                del_loop_info_ = info_.servers[uri_path_].__LOOP__
            end

            if  type(del_loop_info_) == 'table' then
                local found_
                local new_loop_ = { loop=0 }    --排重后的新结构体
                for i=0, #del_loop_info_ do
                    if  del_loop_info_[i] then
                        if  FOO.is_same_ip_port(del_loop_info_[i], tmp_) then
                            found_ = i
                        else
                            -- __LOOP__ 从[0]开始
                            new_loop_[ new_loop_.loop ] = del_loop_info_[i]
                            new_loop_.loop = #new_loop_ + 1   --include [0]
                        end
                    end
                end

                if  found_ then
                    if  new_loop_.loop == 0 then
                        if  functionName_ then
                            info_.servers[uri_path_].act_cmds[functionName_] = nil   --完全清理节点
                        else
                            info_.servers[uri_path_] = nil   --完全清理节点
                        end
                    else
                        if  functionName_ then
                            info_.servers[uri_path_].act_cmds[functionName_].__LOOP__ = new_loop_
                        else
                            info_.servers[uri_path_].__LOOP__ = new_loop_
                        end
                    end

                    gg.return_table( { ret=0, msg='delete_ok',     data=info_.servers[uri_path_] } )

                    FOO.private_save_config( info_, config_file_path_ )  -- 落地存储
                else
                    gg.return_table( { ret=0, msg='delete_before', data=info_.servers[uri_path_] } )
                end
            else
                gg.return_table( { ret=0, msg='no_uri_path_loop', data=info_.servers[uri_path_] } )
            end
        else
            gg.return_table( { ret=0, msg='no_uri_path' } )
        end
    else
        -- 加到config中，目前只有loop模式
        if  not info_.servers[uri_path_] then
            info_.servers[uri_path_] = {}
        end

        local add_loop_info_
        if  functionName_ then
            if  not info_.servers[uri_path_].act_cmds then
                info_.servers[uri_path_].act_cmds = {}
            end
            if  not info_.servers[uri_path_].act_cmds[ functionName_ ] then
                info_.servers[uri_path_].act_cmds[ functionName_ ] = {}
            end
            if  not info_.servers[uri_path_].act_cmds[ functionName_ ].__LOOP__ then
                info_.servers[uri_path_].act_cmds[ functionName_ ].__LOOP__ = { loop=0 }
            end
            add_loop_info_ = info_.servers[uri_path_].act_cmds[ functionName_ ].__LOOP__
        else
            if  not info_.servers[uri_path_].__LOOP__ then
                info_.servers[uri_path_].__LOOP__ = { loop=0 }
            end
            add_loop_info_ = info_.servers[uri_path_].__LOOP__
        end

        -- 排重
        for i=0, #add_loop_info_ do
            if  add_loop_info_[i] then
                if  FOO.is_same_ip_port( add_loop_info_[i], tmp_ ) then
                    log.debug( '__LOOP__ same ip and port, ignore' )
                    gg.return_table( { ret=2, msg='same_server_ip_port', data=info_.servers[uri_path_] } )
                    return
                end
            end
        end

        -- 新增到尾部, 从[0]开始  { [0], [1], [2], loop=3 }
        add_loop_info_[ add_loop_info_.loop ] = tmp_
        add_loop_info_.loop = #add_loop_info_ + 1  --include [0]

        if  functionName_ then
            info_.servers[uri_path_].act_cmds[ functionName_ ].__LOOP__ = add_loop_info_
        else
            info_.servers[uri_path_].__LOOP__ = add_loop_info_
        end

        gg.return_table( { ret=0, msg='add_ok', data=info_.servers[uri_path_] } )

        FOO.private_save_config( info_, config_file_path_ )  -- 落地存储
    end

end


--- 落地存储
function FOO.private_save_config( info_, config_file_path_ )
    uu.set_server_cache_table( 3, __route_servers_cache_key__, info_, 86400 )
    -- /data/centerConfigServer/ma/registerMaGateRoute.lua
    uu.save_table_file( config_file_path_, info_ )
    ns_configMgr.calOneLuaConfigFile( "registerMaGateRoute", ns_config.debug )
end



--- 按path获得完整的路由
function FOO.get_route()
    local path_  = ngx.ctx.m_params.path
    if  not( path_ and #path_ > 2 ) then
        gg.return_table( { ret=99, msg="error_path" } )
        return
    end

    -- 先查找cache
    local info_ = uu.get_server_cache_table( 3, __route_servers_cache_key__ )
    if  not ( info_ and info_.servers) then
        local config_file_path_ = FOO.server_route_config:getFullPath()
        log.debug( 'config_file_path=' .. config_file_path_ )
        info_  = uu.read_table_file( config_file_path_ ) or { servers={} }

        -- 记录cache
        uu.set_server_cache_table( 3, __route_servers_cache_key__, info_, 86400 )
    end

    if  info_.servers[ path_ ] then
        gg.return_table( { ret=0, data=info_.servers[ path_ ] } )
    else
        if  path_ == '_ALL_' then
            gg.return_table( { ret=0, data=info_.servers } )
        else
            gg.return_table( { ret=1, msg="not_found" } )
        end
    end
end



--- 按path彻底清理一个路径
function FOO.clean_route()
    local path_  = ngx.ctx.m_params.path
    if  not( path_ and #path_ > 2 ) then
        gg.return_table( { ret=99, msg="error_path" } )
        return
    end

    local config_file_path_ = FOO.server_route_config:getFullPath()
    log.debug( 'config_file_path=' .. config_file_path_ )

    local info_ = uu.read_table_file( config_file_path_ ) or { servers={} }

    if  info_.servers[path_] then
        info_.servers[path_] = nil

        FOO.private_save_config( info_, config_file_path_ )  -- 落地存储
        gg.return_table( { ret=0, msg="clean_ok" } )
    else
        gg.return_table( { ret=0, msg="not_found" } )
    end

end


return FOO;
